﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using EmailJabber.EmailJabber.Core.Commands.Common;
using EmailJabber.EmailJabber.Core.Entities;
using EmailJabber.Logic.Commands;
using EmailJabber.Logic.Commands.Base;
using EmailJabber.Logic.Logic.Messengers;
using EmailJabber.Logic.Logic.Messengers.EmailMessenger;
using EmailJabber.Logic.Logic.Messengers.JabberMessenger;

namespace EmailJabber.Logic.Logic.BusinessLogic
{
    public class BL
    {
        private IMessenger _jabberClient;
        private IMessenger mailServer;

        object Sync = new object();

        #region State

        private bool AutoSendEmails = true;
        private string admintJabberAddres = string.Empty;
        Dictionary<List<string>, Guid> _jabberBotCommands = new Dictionary<List<string>, Guid>();


        #endregion


        private static BL instance = new BL();

        public static BL Instance
        {
            get
            {
                return instance;
            }
        }

        private BL()
        {
            mailServer = new SmtpServerClass();
            mailServer.MessageRecived += mailServer_MessageRecived;

            _jabberClient = new JabberClient(Properties.Settings.Default.botJid, Properties.Settings.Default.botPassword);
            admintJabberAddres = Properties.Settings.Default.adminJid;
            _jabberClient.MessageRecived += JabberMessageRecived;
        }

        public event EventHandler CurrentStateLog;

        #region message processing
        private void mailServer_MessageRecived(object sender, MessageIM e)
        {
            CommandBase command = CommandManager.Instance.GetCommand(EmailRecived.ID);
            command.Execute(e);
        }

        private void PreProcessCommand(MessageIM message)
        {
            List<PendingCommandEntry> commands = CommandProcessor.Instance.PopCommandsForUser(message.From);
            foreach (PendingCommandEntry command in commands)
            {
            	message.ExtraParameter = command.CommandParameter;
                ExecuteCommandById(command.CommandId, message);
            }
        }

        private void JabberMessageRecived(object sender, MessageIM e)
        {
            string messageBody = e.Body;
            PreProcessCommand(e);
            foreach (KeyValuePair<List<string>, Guid> command in BotCommands)
            {
                bool found = false;
                foreach (string key in command.Key)
                {
                    if (messageBody.StartsWith(key))
                    {
                        messageBody = messageBody.Remove(0, key.Length);
                        CommandBase currentCommand = CommandManager.Instance.GetCommand(command.Value);
                       
                        MessageIM message = new MessageIM(e.From, messageBody, e.To);
                        StartThreadForCommand(message, currentCommand);
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    if (messageBody.StartsWith(command.Value.ToString()))
                    {
                        messageBody = messageBody.Remove(0, command.Value.ToString().Length);
                        CommandBase currentCommand = CommandManager.Instance.GetCommand(command.Value);
                       
                        MessageIM message = new MessageIM(e.From, messageBody, e.To);
                        StartThreadForCommand(message, currentCommand);
                    }
                }
            }
        }

        private void StartThreadForCommand(MessageIM message, CommandBase currentCommand)
        {
            CommandThreadWorker commandThreadWorker = new CommandThreadWorker(currentCommand, message);
            Thread threadCommand = new Thread(commandThreadWorker.Run);
            threadCommand.IsBackground = true;
            threadCommand.Start();
        }
        #endregion message processing

        public void SendMessageToAdmin(string message)
        {
            MessageIM messageForAdmin = new MessageIM(string.Empty, message, admintJabberAddres);
            Send(messageForAdmin);
        }

        public Dictionary<List<string>, Guid> BotCommands
        {
            get { return _jabberBotCommands; }
            set { _jabberBotCommands = value; }
        }

        public void Send(MessageIM message)
        {
            _jabberClient.Send(message);
        }

        /// <summary>
        /// Switch utosend emails
        /// </summary>
        /// <returns></returns>
        public string SwitchAutoUpdates()
        {
            AutoSendEmails = !AutoSendEmails;
            return AutoSendEmails.ToString();
        }

        public void AddLogEntry(LogEntry logEntry)
        {
            lock (Sync)
            {
                DAL.DAL.Instance.AddEntry(logEntry);
            }
        }

        public void SendAutoNotification(MessageIM message)
        {
            if (AutoSendEmails)
            {
                SendMessageToAdmin(message.Body);
            }
        }

        public string AddAliasForCommand(Guid commndId, string[] aliases)
        {
            string result = string.Empty;
            if (aliases != null)
                foreach (string alias in aliases)
                {
                    if (FindCommandIdByAlias(alias).Equals(Guid.Empty))
                    {
                        InsertAliasById(alias, commndId);
                    }
                    else
                    {
                        result = "Alias already in use";
                    }
                }
            return result;
        }

        private void InsertAliasById(string alias, Guid commandId)
        {
            foreach (KeyValuePair<List<string>, Guid> command in _jabberBotCommands)
            {
                if (command.Value.Equals(commandId))
                {
                    command.Key.Add(alias);
                }
            }
        }

        private Guid FindCommandIdByAlias(string alias)
        {
            foreach (KeyValuePair<List<string>, Guid> command in _jabberBotCommands)
            {
                if (command.Key.Contains(alias))
                {
                    return command.Value;
                }
            }
            return Guid.Empty;
        }

        public void ExecuteCommandById(Guid commandId, MessageIM message)
        {
            CommandBase command = CommandManager.Instance.GetCommand(commandId);
            StartThreadForCommand(message, command);
        }

        public string ExtractCommndsFromAssembly(string assemblyFileName)
        {
            string result = string.Empty;
            Assembly sampleAssembly = Assembly.LoadFrom(assemblyFileName);
            Type[] types = sampleAssembly.GetTypes();
            foreach (Type oType in types)
            {
                if (typeof(CommandBase).IsAssignableFrom(oType))
                {
                    CommandBase command = (CommandBase)Activator.CreateInstance(oType);
                    result += command.Description + Environment.NewLine;
                    if (!_jabberBotCommands.ContainsValue(command.Id))
                    {
                        CommandManager.Instance.Register(command);
                        _jabberBotCommands.Add(new List<string>(), command.Id);
                        AddAliasForCommand(command.Id, command.Aliaces);
                    }
                }
            }
            return result;
        }
    }
}